package cn.biplam.common.wrapper.treeFlat.flat;

import java.util.ArrayList;

import cn.biplam.common.wrapper.treeFlat.PcNode;
import cn.biplam.common.wrapper.treeFlat.flat.callback.OperatorTypeFilterCallback;


/**
 *  树数据-Flat数据<BR>
 *  <P>
 *  用法:<BR>
 *  	TreeFlat(TreeNode) 传入树形数据<BR>
 *  	setOperatorTypeFilterCallback(callback) 设置需要被过滤的节点<BR>
 *      String[][] get()   返回平面化数据<BR>
 *      int getDepth()    返回树的深度<BR>
 *  </P>
 *  <P> 
 *   平面化后数据为:<BR>
 *   <TABLE border='1'>
 *      <TR> <TD>当前节点(ID、名称、级别,类型)</TD> <TD>父亲1</TD> <TD>父亲2</TD> <TD>    </TD> </TR>
 *      <TR> <TD>当前节点(ID、名称、级别,类型)</TD> <TD>父亲1</TD> <TD>父亲2</TD> <TD>父亲3</TD>  </TR>
 *    </TABLE><BR>
 *    节点的顺序为: 深度优先遍历顺序(即先是当前节点,再是儿子,再是兄弟)
 *  </P>
 * @author XiaoRuxing Nov 21, 200911:17:54 AM
 * @version 1.0
 */
public class TreeFlat{

	private int depth=-1;
	/** 平面化数据列表 */
	private String[][] flatDataList;

	private ArrayList<FlatTreeNode> flatData;
	
	private FlatTreeNode curFlatNode;
	/** 当前节点数据 */
	private PcNode data;

	/** 节点信息字段个数 */
	private static final int REGULAR_FIELD_NUMB = 4;
	/** 按节点类型过滤回调器,返回的数据将按节点类型过滤 */
	private OperatorTypeFilterCallback operatorTypeFilter;
	
	/** 当前平面化数据逐行读取下标指示器 */
	private int curFlatDataNumb=-1;
	
	/**
	 *  构造方法
	 * @param data 树节点数据
	 */
	public TreeFlat(PcNode data){
		this.data = data;
		this.flatData = new ArrayList<FlatTreeNode>();
	}

	/**
	 * @return 平面化数据
	 */
	public String[][] get(){
		if(this.flatDataList==null)
			this.getAllData();
		return this.flatDataList;
	}

	/**
	 * @return 树的深度
	 */
	public int getDepth(){
		if(this.flatData==null)
			this.execute();
		return this.depth;
	}

	/**
	 *  设置节点操作类型过滤回调器
	 */
	public void setOperatorTypeFilterCallback(OperatorTypeFilterCallback callback){
		this.operatorTypeFilter = callback;
	}
	
	/**
	 *  执行树形结构到平面化结构转换
	 */
	public void execute(){
		if(this.data==null)return;
		//获取当前树平面化数据
		if(data.nodeID ==null){
			traversal(data, null);//不包含头节点
		}else{
			traversal(data,createFlatNode(data, null));//包含头节点
		}
	}

	/**
	 *  获取当前游标指向的数据,执行前先移动游标
	 * @return 返回当前游标指向的数据
	 */
	public String [] getCurentNode(){
		if(this.flatDataList == null){
			this.flatDataList = new String[this.flatData.size()][];
		}
		if(this.flatDataList[this.curFlatDataNumb]==null){
			this.flatDataList[this.curFlatDataNumb] =
				flatNodeToArrray(this.flatData.get(this.curFlatDataNumb));
		}
		return this.flatDataList[this.curFlatDataNumb];
	}
	
	/**
	 * 遍历数据集前先调用execute()获取数据<BR>
	 * 访问所有节点的游标后移一位<BR>
	 * @return 如果平面记录集无数据,或者已经到最后一行返回false,否则返回true
	 */
	public boolean next(){
		if(this.flatData==null
				|| this.curFlatDataNumb > this.flatData.size()-2){
			return false;
		}else{
			this.curFlatDataNumb++;
			return true;
		}
	}
	
	/**
	 *  获取所有数据
	 */
	private void getAllData(){
		this.execute();
		//将平面化数据放入数组
		this.getArrayData();
	}
	
	/**
	 *  将节点字段顺序进行排序
	 */
	private void getArrayData(){
		this.flatDataList = new String[this.flatData.size()][];
		int i = 0; //当前节点下标
		for(FlatTreeNode node:this.flatData){
			flatDataList[i] = flatNodeToArrray(node);
			i++;
		}
	}
	
	/**
	 *  当个节点信息<BR>
	 *  顺序为:节点ID,节点名称,节点级别,节点所有父亲
	 */
	private String [] flatNodeToArrray(FlatTreeNode node){
		String [] nodeData = new String[this.depth*2+REGULAR_FIELD_NUMB];
		nodeData[0] = node.nodeId;
		nodeData[1] = node.nodeName;
		nodeData[2] = node.nodeLevel;
		nodeData[3] = node.operatorType;
		int numb=REGULAR_FIELD_NUMB;
		for(int i=0;i<node.parents.size();i++){
			nodeData[i+numb] = node.parents.get(i)[0];//N级父亲ID
		}
		numb = numb+this.depth;
		for(int i=0;i<node.parents.size();i++){
			nodeData[i+numb] = node.parents.get(i)[1];//N级父亲名称
		}
		return nodeData;
	}
	
	/**
	 *  遍历树
	 * @param node 树节点
	 */
	private void traversal(PcNode node,FlatTreeNode parent){
		if(node.children == null || node.children.size()<1){
			return;
		}
		for(PcNode curNode:node.children){
			//获取节点
			createFlatNode(curNode, parent);
			//获取节点的所有儿子
			traversal(curNode, curFlatNode);
		}
	}

	/**
	 * @return 创建单个节点
	 */
	private FlatTreeNode createFlatNode(PcNode curNode,FlatTreeNode parent){
		//创建节点
		curFlatNode = new FlatTreeNode();
		curFlatNode.nodeId = curNode.nodeID;
		curFlatNode.nodeName = curNode.nodeName;
		curFlatNode.nodeLevel = String.valueOf(curNode.nodeLevel);
		curFlatNode.operatorType = curNode.nodeOperatorType;
		if(parent!=null){
			curFlatNode.parents = new ArrayList<String[]>(parent.parents);
		}else{
			curFlatNode.parents = new ArrayList<String[]>();
		}
		if(curNode.parent.nodeID!=null){
			curFlatNode.parents.add(new String[]{curNode.parent.nodeID,
					curNode.parent.nodeName});
		}
		//计算树的深度
		_setDepth(curFlatNode);
		//将节点放入平面化数据列表中
		if(this.operatorTypeFilter==null||
				!operatorTypeFilter.isFilter(curFlatNode.operatorType)){//节点未被过滤
			flatData.add(curFlatNode);
		}
		return curFlatNode;
	}

	/**
	 *  设置树的深度
	 */
	private void _setDepth(FlatTreeNode flatNode){
		int curDepth =  flatNode.parents.size();
		if(curDepth>this.depth){
			this.depth = curDepth;
		}
	}

	/**
	 * 树平面化结构
	 */
	private class FlatTreeNode{
		//节点ID
		String nodeId;
		//节点名称
		String nodeName;
		//节点级别
		String nodeLevel;
		/** 节点类型 */
		String operatorType;
		//节点父亲们
		ArrayList<String[]> parents;
	}
}
